package com.yzq.os.spider.v.service.domain;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.ClassUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.BeanInstantiationException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;

import com.yzq.os.spider.v.dao.SearchEngineParamDao;
import com.yzq.os.spider.v.domain.SearchEngine;
import com.yzq.os.spider.v.domain.SearchEngineParam;
import com.yzq.os.spider.v.service.queryurl.placeholder.PlaceHolder;

@Service
public class SearchEngineParamService {

	private static Logger logger = Logger.getLogger(SearchEngineParamService.class);
	@Autowired
	private SearchEngineParamDao searchEngineParamDao;

	@Value("${app.path.placeHolder.implements.class}")
	private String placeHolderClassPackage;

	private Map<String, String> placeholderMap = new ConcurrentHashMap<String, String>();

	public void save(SearchEngineParam searchEngineParam) {
		searchEngineParamDao.save(searchEngineParam);
	}

	public SearchEngineParam findById(int searchEngineParamId) {
		return searchEngineParamDao.findByPkId(searchEngineParamId);
	}

	public void update(SearchEngineParam searchEngineParam) {
		searchEngineParamDao.update(searchEngineParam);
	}

	public List<SearchEngineParam> findBySearchEngineId(int searchEngineId) {
		return searchEngineParamDao.findBySearchEngineId(searchEngineId);
	}

	public List<SearchEngineParam> findSingleValueRequired(int searchEngineId) {
		return searchEngineParamDao.findList(searchEngineId, 1, 1);
	}

	public List<SearchEngineParam> findMultipleValueRequired(int searchEngineId) {
		return searchEngineParamDao.findList(searchEngineId, 0, 1);
	}

	public List<SearchEngineParam> findMultipleValueNoRequired(int searchEngineId) {
		return searchEngineParamDao.findList(searchEngineId, 0, 0);
	}

	@SuppressWarnings("unchecked")
	private synchronized void checkInitMap() {
		synchronized (placeholderMap) {
			if (MapUtils.isEmpty(placeholderMap)) {

				List<String> classes = getClassPaths(placeHolderClassPackage);
				if (CollectionUtils.isNotEmpty(classes)) {
					for (String clazz : classes) {
						try {
							PlaceHolder holder = BeanUtils.instantiate(ClassUtils.getClass(clazz));
							logger.info("Init place holder key:[" + holder.returnPlaceString() + "] class [" + clazz + "]");
							placeholderMap.put(holder.returnPlaceString(), clazz);
						} catch (BeanInstantiationException e) {
							logger.info("clazz:[" + clazz + "] bean instantiation exception to pass.");
						} catch (ClassNotFoundException e) {
							logger.error("clazz:[" + clazz + "]", e);
						}
					}
				} else {
					logger.info("Not place holder classes. placeHolderClassPackage:[" + placeHolderClassPackage + "]");
				}

			}
		}
	}

	public List<String> getplaceholdersUI() {
		List<String> returnList = new ArrayList<String>();
		checkInitMap();
		if (MapUtils.isNotEmpty(placeholderMap)) {
			returnList.addAll(placeholderMap.keySet());
		}
		Collections.sort(returnList);
		return returnList;
	}

	private List<String> getClassPaths(String baseClasspath) {
		List<String> returnValues = new ArrayList<String>();
		try {
			File dir = ResourceUtils.getFile("classpath:" + baseClasspath);
			if (dir != null && dir.isDirectory() && dir.exists()) {
				Collection<File> files = FileUtils.listFiles(dir, new String[] { "class" }, false);
				if (CollectionUtils.isNotEmpty(files)) {
					String basePackageName = StringUtils.replaceEach(baseClasspath, new String[] { "/", "\\" }, new String[] { ".", "." });
					for (File file : files) {
						String clazz = basePackageName + "." + FilenameUtils.getBaseName(file.getName());
						returnValues.add(clazz);
					}
				} else {
					logger.info("Not have files under path:[" + dir.getAbsolutePath() + "]");
				}
			} else {
				logger.error("Dir file object is null........");
			}
		} catch (FileNotFoundException e) {
			logger.error("", e);
		}
		return returnValues;
	}

	public List<String> getValueList(String value, SearchEngine searchEngine) throws UnsupportedEncodingException {
		String urlEncode = SearchEngineService.getEncode(searchEngine.getUrlEncode());
		String replaceString = "[TEMP_REPLACE_STRING]";
		List<String> result = new ArrayList<String>();
		if (StringUtils.isBlank(value)) {
			result.add("");
		} else {
			String[] lines = StringUtils.split(value, "\n");
			for (String line : lines) {
				if (StringUtils.isNotBlank(line)) {
					line = StringUtils.replace(line, "\\*,*\\", replaceString);
					String code = StringUtils.substringBefore(line, ",");
					code = StringUtils.trim(code);// trim \n
					if (StringUtils.isNotBlank(code)) {
						code = StringUtils.replace(code, replaceString, ",");
						result.add(URLEncoder.encode(code, urlEncode));
					} else {
						line = StringUtils.replace(line, replaceString, ",");
						result.add(URLEncoder.encode(line, urlEncode));
					}
				}
			}
		}
		return result;
	}

	public String replaceHolder(String value, String encode) {
		String returnValue = value;
		checkInitMap();
		if (MapUtils.isNotEmpty(placeholderMap)) {
			for (String key : placeholderMap.keySet()) {
				try {
					String encodedKey = URLEncoder.encode(key, encode);
					if (StringUtils.contains(returnValue, encodedKey)) {
						returnValue = replace(returnValue, placeholderMap.get(key), encode);
					}
				} catch (UnsupportedEncodingException e) {
					logger.error("", e);
				}
			}
		}
		return returnValue;
	}

	@SuppressWarnings("unchecked")
	private String replace(String value, String clazz, String encode) {
		String returnValue = value;
		try {
			PlaceHolder holder = BeanUtils.instantiate(ClassUtils.getClass(clazz));
			holder.setUrlEncode(encode);
			returnValue = holder.replace(value);
		} catch (BeanInstantiationException e) {
			logger.error("", e);
		} catch (ClassNotFoundException e) {
			logger.error("", e);
		}
		return returnValue;
	}

	public static void main(String[] args) throws UnsupportedEncodingException {
		String xx = "<<yyyy-MM-dd>>";
		String yy = URLEncoder.encode(xx, "UTF-8");
		System.out.println(yy);
	}

	public void deleteBySearchEngineId(Integer searchEngineId) {
		searchEngineParamDao.deleteBySearchEngineId(searchEngineId);
	}

}
